package com.gzsxy.esjy.gateway.filter;

import com.gzsxy.esjy.common.base.exception.impl.CustomAssert;
import com.gzsxy.esjy.common.base.util.JwtUtils;
import com.gzsxy.esjy.common.base.util.UriUtil;
import com.gzsxy.esjy.gateway.config.properties.GateWayProperties;
import com.gzsxy.esjy.gateway.service.GlobalService;
import com.gzsxy.esjy.redis.user.AuthContants;
import com.gzsxy.esjy.redis.user.ISystemUser;
import com.gzsxy.esjy.service.base.DictionaryConstants;
import lombok.extern.slf4j.Slf4j;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;

/**
 * @author xiaolong
 * @version 1.0
 * @description: GateWay中的Filter过滤器
 * @date 2021/9/20 21:02
 */
@Component
@Slf4j
public class GateWayFilter implements GlobalFilter, Ordered {

    @Autowired
    private GateWayProperties properties;

    @Autowired
    private GlobalService globalService;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {

//        log.info("********come in MyLogGateWayFilter: " + new Date());
//        //必须在请求参数传一个uname 值；
//        String uname = exchange.getRequest().getQueryParams().getFirst("uname");
//        if (uname == null) {
//            log.info("*********用户名为null，非法用户，");
//            exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);
//            return exchange.getResponse().setComplete();
//        }
        ServerHttpRequest request = exchange.getRequest();
        //获取真实路径
        String uri = request.getURI().getPath();

        //判断路径中如果含有 /api/**/auth/**,处理前台token需要鉴权
        AntPathMatcher antPathMatcher = new AntPathMatcher();
        //前台过滤
        if (antPathMatcher.match("/**/api/**", uri)){
            //过滤前台token
            if(!apiCheckUri(uri)) {
                //获取token
                String access_token = getToken(request);
                if (StringUtils.isEmpty(access_token)){
                    ServerHttpResponse response = exchange.getResponse();
                    return out(response);
                }
                //token校验失败
                boolean isCheck = JwtUtils.checkJwtTToken(access_token);
                if (!isCheck){
                    ServerHttpResponse response = exchange.getResponse();
                    return out(response);
                }
            }
            return chain.filter(exchange);
        } else {
            String auth = null;

            if (!checkUri(uri)){
                String access_token = getToken(request);
                CustomAssert.notBlank(access_token,"用户未登录",403);
                //鉴权
                ISystemUser loginUser = globalService.getLoginUser(access_token, exchange);
                CustomAssert.notNull(loginUser,"用户登录已过期",403);
                exchange.getAttributes().put(AuthContants.AUTH_PASS,loginUser.getUserAccout());

                // 下发鉴权通过标识
                if (org.apache.commons.lang3.StringUtils.isNotBlank(loginUser.getUserAccout())){
                    auth = loginUser.getUserName() + "&" +loginUser.getUserAccout() + "&" +loginUser.getRoles();

                    try {
                        auth = URLEncoder.encode(auth, Charset.defaultCharset().name());
                        //request.mutate().header()向headers请求头中放文件，记得build
                        //exchange.mutate().request()将现在的request 变成 change对象
                        return chain.filter(exchange.mutate().request(request.mutate().header(AuthContants.AUTH_PASS,auth).build()).build());
                    } catch (UnsupportedEncodingException e) {
                        CustomAssert.notTrue(false,e.getMessage(),500,e);
                    }
                }

            }
            return chain.filter(exchange);
        }
    }



    /**
     * @description: 后台判断uri是否被排除
     * @param
     * @return
     */
    private boolean checkUri(String uri){
        return properties.getExcluteAuthPaths().stream().anyMatch((pattern) -> UriUtil.isUrlMatches(pattern,uri));
    }

    /**
     * @description: 前台判断uri是否被排除
     * @param
     * @return
     */
    private boolean apiCheckUri(String uri){
        return properties.getApiExcluteAuthPaths().stream().anyMatch((pattern) -> UriUtil.isUrlMatches(pattern,uri));
    }


    /**
     * @description: 定义当前过滤器的优先级（值越小优先级越高）必须小于负一
     * @param
     * @return
     */
    @Override
    public int getOrder() {
        return -1;
    }

    /**
     * @description: 获取token
     * @param
     * @return
     */
    private String getToken(ServerHttpRequest request){

        //从请求参数中获取access_token值
        String token = request.getQueryParams().getFirst(AuthContants.TOKEN);
        //为空
        if (!StringUtils.hasText(token)){
            //从请求头拿Authorization
            token = request.getHeaders().getFirst(AuthContants.TOKEN_HEADER);
            //为空
            if (!StringUtils.hasText(token)){
                //从请求头拿access_token
                token = request.getHeaders().getFirst(AuthContants.TOKEN);
            }
            //不为空
            if (StringUtils.hasText(token)){
                //分割 如果是通过Authorization拿到的token是Bearer 544f80ad-bef7-4750-a1f5-a055a4306ea0
                String[] s = token.split(" ");
                if (s.length >1){
                    token = s[1];
                }
            }
        }
        return token;

    }



    //使用webflux输入请求信息
    private Mono<Void> out(ServerHttpResponse response) {
        JSONObject message = new JSONObject();
        message.put("success", false);
        message.put("code", DictionaryConstants.NUMBER_403);
        message.put("data", "");
        message.put("message", "鉴权失败");
        byte[] bytes = message.toString().getBytes(StandardCharsets.UTF_8);
        DataBuffer buffer = response.bufferFactory().wrap(bytes);
        //指定编码，否则在浏览器中会中文乱码
        response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
        //输出http响应
        return response.writeWith(Mono.just(buffer));
    }


}
